﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace GeneralClasses
{
    /// <summary>
    /// Populates a database with random data.  Used for testing purposes. 
    /// </summary>
    public class DataGen
    {
        Random rnd;

        DatabaseConnection dbc;
        private int numPersons;
        private int numManagers;

        //Parameters for generating a Person
        private List<string> firstNames;
        private List<string> middleNames;
        private List<string> lastNames;
        private List<string> passwords;
        private List<string> suffixes;
        private List<string> streetNames;
        private List<int> approxHours;

        private List<Person> persons;
        private List<Department> departments;
        private List<PayGrade> payGrades;
        private List<Shift> shifts;
        private List<Title> titles;

        public DataGen(DatabaseConnection dbc, int numPersons, int numManagers, List<string> firstNames, 
            List<string> middleNames, List<string> lastNames, List<string> passwords, List<string> suffixes, 
            List<string> streetNames, List<int> approxHours, List<Department> departments, 
            List<PayGrade> payGrades, List<Shift> shifts, List<Title> titles)
        {
            rnd = new Random(DateTime.Today.Millisecond);

            this.dbc = dbc;
            this.numPersons = numPersons;
            this.numManagers = numManagers;

            this.firstNames = firstNames;
            this.middleNames = middleNames;
            this.lastNames = lastNames;
            this.passwords = passwords;
            this.suffixes = suffixes;
            this.streetNames = streetNames;
            this.approxHours = approxHours;

            this.persons = new List<Person>();
            this.departments = departments;
            this.payGrades = payGrades;
            this.shifts = shifts;
            this.titles = titles;
        }

        public DataGen(DatabaseConnection dbc, List<Person> persons, List<Department> departments,
            List<PayGrade> payGrades, List<Shift> shifts, List<Title> titles)
        {
            this.rnd = new Random(DateTime.Today.Millisecond);

            this.dbc = dbc;

            this.persons = persons;
            this.departments = departments;
            this.payGrades = payGrades;
            this.shifts = shifts;
            this.titles = titles;
        }

        public void PopulateComplete()
        {
            PopulateComplete(true, true, true, true, true, true);
        }

        /// <summary>
        /// Populates all relevant tables and relationship tables with random data.
        /// </summary>
        public void PopulateComplete(bool populateDayOfWeek, bool populatePerson, bool populateDepartment, 
            bool populatePayGrade, bool populateShift, bool populateTitle)
        {
            if(populateDayOfWeek)
                PopulateDayOfWeek();
            if(populatePerson)
                PopulatePerson();
            if(populateDepartment)
                PopulateDepartment();
            if (populatePayGrade)
                PopulatePayGrade();
            if (populateShift)
                PopulateShift();
            if (populateTitle)
                PopulateTitle();
        }

        public void PopulateDayOfWeek()
        {
            dbc.executeNonQuery("INSERT INTO DayOfWeek (letter, name) VALUES     ('M', 'Monday');");
            dbc.executeNonQuery("INSERT INTO DayOfWeek (letter, name) VALUES     ('T', 'Tuesday');");
            dbc.executeNonQuery("INSERT INTO DayOfWeek (letter, name) VALUES     ('W', 'Wednesday');");
            dbc.executeNonQuery("INSERT INTO DayOfWeek (letter, name) VALUES     ('R', 'Thursday');");
            dbc.executeNonQuery("INSERT INTO DayOfWeek (letter, name) VALUES     ('F', 'Friday');");
            dbc.executeNonQuery("INSERT INTO DayOfWeek (letter, name) VALUES     ('S', 'Saturday');");
            dbc.executeNonQuery("INSERT INTO DayOfWeek (letter, name) VALUES     ('S', 'Sunday');");
        }

        /// <summary>
        /// Populates Person table with random data.
        /// </summary>
        public void PopulatePerson()
        {
            Person person;
            int numManagers = this.numManagers;

            for (int i = 0; i < numPersons; i++)
            {
                person = new Person();
                if (numManagers > 0)
                {
                    person.IsManager = true;
                    numManagers--;
                }
                person.Active = true;
                person.Address = Convert.ToString(rnd.Next(100, 2000)) + " " +
                    streetNames[rnd.Next(streetNames.Count)];
                person.ApproxHours = approxHours[rnd.Next(approxHours.Count)];
                person.CellPhone = Convert.ToString(rnd.Next(100, 1000)) + "-" + 
                    Convert.ToString(rnd.Next(100, 999)) + "-" + Convert.ToString(rnd.Next(1000, 9999));
                person.DBC = dbc;
                person.FirstName = firstNames[rnd.Next(firstNames.Count)];
                person.HomePhone = Convert.ToString(rnd.Next(100, 1000)) + "-" +
                    Convert.ToString(rnd.Next(100, 999)) + "-" + Convert.ToString(rnd.Next(1000, 9999));
                person.LastName = lastNames[rnd.Next(lastNames.Count)];
                person.MiddleName = middleNames[rnd.Next(middleNames.Count)];
                person.Password = passwords[rnd.Next(passwords.Count)];
                person.Suffix = suffixes[rnd.Next(suffixes.Count)];
                person.Username = person.FirstName[0].ToString().ToLower() + 
                    person.MiddleName[0].ToString().ToLower() +
                    person.LastName[0].ToString().ToLower() + Convert.ToString(persons.Count);
                person.saveDataSimple();
                persons.Add(person);
            }
        }

        public void PopulateDepartment()
        {
            foreach (Department department in departments)
            {
                department.DepartmentID = department.saveDataSimple();
            }
        }

        public void PopulatePayGrade()
        {
            foreach (PayGrade payGrade in payGrades)
            {
                payGrade.PayGradeID = payGrade.saveData();
            }
        }

        public void PopulateShift()
        {
            foreach (Shift shift in shifts)
            {
                shift.ShiftID = shift.saveDataSimple();
            }
        }

        public void PopulateTitle()
        {
            foreach (Title title in titles)
            {
                title.TitleID = title.saveDataSimple();
            }
        }

        //TODO: Create populate functions for relationship tables.

        /// <summary>
        /// Preconditions: titles and persons array initialized in constructor.
        /// Postconditions: Creates a new random relationship for all Persons
        /// who don't have a Title and assigns them Titles.
        /// </summary>
        public void PopulatePersonHasTitle()
        {
            int titleID;

            foreach (Person person in persons)
            {
                if (person.TitleTableIDs.Count <= 0)
                {
                    titleID = titles[rnd.Next(titles.Count)].TitleID;
                    person.TitleTableIDs.Add(titleID);
                    dbc.executeNonQuery("INSERT INTO personhastitlerelationship " +
                        "(perid,tid) values ('" + person.PERID + "','" + titleID + "')");
                }
            }
        }

        /// <summary>
        /// Preconditions: payGrades and persons array initialized in constructor.
        /// Postconditions: Creates a new random relationship for all Persons
        /// who don't have a PayGrade and assigns them PayGrades.
        /// </summary>
        public void PopulatePersonHasPayGrade()
        {
            int payGradeID;

            foreach (Person person in persons)
            {
                if (person.PayGradeTableID <= 0)
                {
                    payGradeID = payGrades[rnd.Next(payGrades.Count)].PayGradeID;
                    person.PayGradeTableID = payGradeID;
                    dbc.executeNonQuery("INSERT INTO personhaspaygraderelationship " +
                        "(perid,paid) values ('" + person.PERID + "','" + payGradeID + 
                        "')");
                }
            }
        }

        /// <summary>
        /// Preconditions: departments and persons array initialized in constructor.
        /// Postconditions: Creates a new random relationship for all Persons
        /// who don't have a Department and assigns them Departments.
        /// </summary>
        public void PopulatePersonHasDepartment()
        {
            int depID;

            foreach (Person person in persons)
            {
                if (person.DepartmentTableIDs.Count <= 0)
                {
                    depID = departments[rnd.Next(departments.Count)].DepartmentID;
                    person.DepartmentTableIDs.Add(depID);
                    dbc.executeNonQuery("INSERT INTO personhasdepartmentrelationship (perid,deid) values " +
                        "('" + person.PERID + "','" + depID + "')");
                }
            }
        }

        /// <summary>
        /// Preconditions: persons array initialized in constructor.  There 
        /// is at least one manager in the persons array.
        /// Postconditions: Creates a new random relationship for all Persons
        /// who don't have a manager and assigns them a manager.
        /// </summary>
        public void PopulatePersonHasSuperior()
        {
            int supID, alphaID;
            List<Person> managers = new List<Person>();

            foreach (Person person in persons)
            {
                if (person.IsManager)
                    managers.Add(person);
            }

            alphaID = managers[rnd.Next(managers.Count)].PERID;

            foreach (Person person in persons)
            {
                if (person.SuperiorID <= 0)
                {
                    if (!person.IsManager)
                    {
                        supID = managers[rnd.Next(managers.Count)].PERID;
                        person.SuperiorID = supID;
                        dbc.executeNonQuery("INSERT INTO personhassuperiorrelationship (peridA,peridB) " +
                            "values ('" + person.PERID + "','" + supID + "')");
                    }
                    else
                    {
                        person.SuperiorID = alphaID;
                        dbc.executeNonQuery("INSERT INTO personhassuperiorrelationship (peridA,peridB) " +
                            "values ('" + person.PERID + "','" + alphaID + "')");
                    }
                }
            }
        }
    }
}
